#include "../include/event_loop.h"
#include <assert.h>

void event_loop::HandlerEvent(int num)
{
    int n = num;
    io_event_map_it ev_it; // 遍历map的迭代器
    for (int i = 0; i < n; i++)
    {
        ev_it = _evs.find(_fired_evs[i].data.fd);
        assert(ev_it != _evs.end());
        io_event *ie = &(ev_it->second);
        // 读事件就绪
        if (_fired_evs[i].events & EPOLLIN)
        {
            void *args = ie->rcb_args;
            ie->read_callback(this, _fired_evs[i].data.fd, args);
        }
        // 写事件就绪
        else if (_fired_evs[i].events & EPOLLOUT)
        {
            void *args = ie->wcb_args;
            ie->write_callback(this, _fired_evs[i].data.fd, args);
        }
        else if (_fired_evs[i].events & (EPOLLHUP | EPOLLERR))
        {
            // 水平触发模式的情况
            //  水平触发未处理，可能会出现HUP事件，正常处理读写，没有则清空
            if (ie->read_callback != NULL)
            {
                void *args = ie->rcb_args;
                ie->read_callback(this, _fired_evs[i].data.fd, args);
            }
            else if (ie->write_callback != NULL)
            {
                void *args = ie->wcb_args;
                ie->write_callback(this, _fired_evs[i].data.fd, args);
            }
            else
            {
                // 删除
                fprintf(stderr, "fd %d get error, delete it from epoll\n", _fired_evs[i].data.fd);
                this->del_io_event(_fired_evs[i].data.fd);
            }
        }
    }
}

void event_loop::Dispatcher()
{
    int n = Epoller::LoopOnce(_epfd, _fired_evs, MAXEVENTS);
    if (n > 0)
    {
        HandlerEvent(n);
    }
}

event_loop::event_loop()
{
    _epfd = Epoller::CreateEpoller();
}

// 阻塞循环处理事件
void event_loop::event_process()
{
    while (true)
    {
        Dispatcher();
    }
}

/*
 * 处理的事件机制是
 * 如果EPOLLIN 在mask中， EPOLLOUT就不允许在mask中
 * 如果EPOLLOUT 在mask中， EPOLLIN就不允许在mask中
 * 如果想注册EPOLLIN|EPOLLOUT的事件， 那么就调用add_io_event() 方法两次来注册。
 * */
void event_loop::add_io_event(int fd, io_callback *proc, int mask, void *args)
{
    int final_mask;
    int op;

    // 1 找到当前fd是否已经有事件
    io_event_map_it it = _evs.find(fd);
    if (it == _evs.end())
    {
        // 2 如果没有操作动作就是ADD
        // 没有找到
        final_mask = mask;
        op = EPOLL_CTL_ADD;
    }
    else
    {
        // 3 如果有操作董酒是MOD
        // 添加事件标识位
        final_mask = it->second.mask | mask;
        op = EPOLL_CTL_MOD;
    }

    // 4 注册回调函数
    if (mask & EPOLLIN)
    {
        // 读事件回调函数注册
        _evs[fd].read_callback = proc;
        _evs[fd].rcb_args = args;
    }
    else if (mask & EPOLLOUT)
    {
        _evs[fd].write_callback = proc;
        _evs[fd].wcb_args = args;
    }

    // 5 epoll_ctl添加到epoll堆里
    _evs[fd].mask = final_mask;
    Epoller::AddEvent(_epfd, fd, final_mask);
    // 6 将fd添加到监听集合中
    _listenfds.insert(fd);
}

void event_loop::del_io_event(int fd)
{
    _evs.erase(fd);
    _listenfds.erase(fd);
    Epoller::DelEvent(_epfd, fd);
}

void event_loop::del_io_event(int fd, int mask)
{
    // 如果没有该事件，直接返回
    io_event_map_it it = _evs.find(fd);
    if (it == _evs.end())
    {
        return;
    }

    int &o_mask = it->second.mask;
    // 修正mask
    o_mask = o_mask & (~mask);

    if (o_mask == 0)
    {
        // 如果修正之后 mask为0，则删除
        this->del_io_event(fd);
    }
    else
    {
        // 如果修正之后，mask非0，则修改
        Epoller::ModEvent(_epfd, fd, o_mask);
    }
}
